/*
	Author: Michael Kremser, Gabriele Amstler
	Date: 2011/11/28
	Task description:
		http://code.google.com/p/fh-kapfenberg--swd09--linux-systemnah/wiki/HomeworkProcessLifetime
	References:
		http://www.linuxprogrammingblog.com/c-language
		http://www.unix.com/programming/134846-read-write-stdin-stdout-unix.html
*/

#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/wait.h>
#include <stdlib.h>

int signal_from_child = 0;

static void hdl(int sig)
{
	signal_from_child = 1;
}

int main(char** args)
{
	pid_t child = fork(), w;
	unsigned char c;
	// Forks the process, the child process starts at this position
	if (child == 0)
	{
		printf("I am the child!\n");
		printf("How would you like me to die?\n");
		printf("0 = Normal exit\n");
		printf("1 = Exit w/ return code\n");
		printf("2 = Abort\n");
		printf("3 = Floating point exception\n");
		int c1, valid = 0, exitcode, yyy, zero = 0;
		do
		{
			printf("\nEnter number followed by the return key: ");
			c1 = getchar();
			switch (c1)
			{
				case '0':
					valid = 1;
					break;
				case '1':
					do
					{
						printf("\nPlease enter exit code (0 < exit code < 256): ");
						scanf("%d", &exitcode);
						printf("");
					} while (exitcode < 1 || exitcode > 255);
					exit(exitcode);
				case '2':
					abort();
				case '3':
					yyy = 123 / zero;
				default:
					printf("\nPlease enter 0, 1, 2, or 3!\n");
			}
		} while (valid == 0);
		printf("Child dies now\n");
		// send signal to parent
	}
	else
	{
		printf("My child's PID is %d\n", child);
		int status;
		
		struct timespec ts_wait;
		memset(&ts_wait, 0, sizeof(ts_wait));
		ts_wait.tv_nsec = 1000000; // 1 ms
		
		struct sigaction act;
		memset(&act, 0, sizeof(act));
		act.sa_handler = hdl;
		if (sigaction(SIGCHLD, &act, 0)) {
			perror ("sigaction");
			return 1;
		}
		
		do
		{
			nanosleep(&ts_wait, NULL);
		} while (signal_from_child == 0);
		printf("Child died... now look what `ps` says!\n");
		int c2 = getchar();
		// ref: man waitpid, man strsignal
		w = waitpid(child, &status, WUNTRACED | WCONTINUED);
		if (w == -1) {
			perror("waitpid");
			exit(EXIT_FAILURE);
		}

		if (WIFEXITED(status)) {
			printf("exited, status=%d\n", WEXITSTATUS(status));
		} else if (WIFSIGNALED(status)) {
			printf("killed by signal %s\n", strsignal(WTERMSIG(status)));
		} else if (WIFSTOPPED(status)) {
			printf("stopped by signal %d\n", WSTOPSIG(status));
		} else if (WIFCONTINUED(status)) {
			printf("continued\n");
		}
		printf("\nParent has done its work.\n");
	}
}
